package com.lwc.cfdns.exception;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lwc.cfdns.enums.ResultCode;
import com.lwc.cfdns.utils.ResultUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * 统一异常处理及统一格式返回
 *
 * @author luwc
 * @title BadException
 * @description
 * @time 2023/4/22 09:43:08
 * @version: 1.0
 */
@RestControllerAdvice
public class GlobalException implements ResponseBodyAdvice<Object> {
    /**
     * 统一处理
     *
     * @param exception
     * @return ResultUtils
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/4/22 09:44:19
     */
    @ExceptionHandler
    public ResultUtils HandleException(Exception exception) {
        String message = exception.getMessage();
        int code = ResultCode.ERROR.getCode();
        // POST
        if (exception instanceof MethodArgumentNotValidException) {
            //验证器异常处理
            message = ((MethodArgumentNotValidException) exception).getFieldError().getDefaultMessage();
        }
        // GET
        if (exception instanceof BindException) {
            message = ((BindException) exception).getFieldError().getDefaultMessage();
        }
        // Spring Security 没有权限异常
        if (exception instanceof AccessDeniedException) {
            code = ResultCode.AUTH_FORBIDDEN.getCode();
            message = ResultCode.AUTH_FORBIDDEN.getMessage();
        }
        System.out.println(exception);
        return ResultUtils.of(code, message, null, System.currentTimeMillis() / 1000);
    }

    /**
     * 授权异常
     *
     * @param e
     * @return ResultUtils
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/4/24 17:19:02
     */
    @ExceptionHandler(AuthException.class)
    public ResultUtils AuthException(AuthException e) {
        return ResultUtils.of(e.getCode(), e.getMessage(), null, System.currentTimeMillis() / 1000);
    }

    /**
     * 通用异常
     *
     * @param e
     * @return ResultUtils
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/4/28 14:14:23
     */
    @ExceptionHandler(BadException.class)
    public ResultUtils BadException(BadException e) {
        return ResultUtils.of(e.getCode(), e.getMessage(), null, System.currentTimeMillis() / 1000);
    }

    /**
     * 数据库异常
     *
     * @param e
     * @return ResultUtils
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/4/28 14:14:23
     */
    @ExceptionHandler(DbTransactionException.class)
    public ResultUtils DbtransactionException(DbTransactionException e) {
        return ResultUtils.of(e.getCode(), e.getMessage(), null, System.currentTimeMillis() / 1000);
    }

    /**
     * 搜索条件没数据直接返回前端处理
     *
     * @param e
     * @return ResultUtils
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/5/30 09:24:17
     */
    @ExceptionHandler(NullDataOfSearchException.class)
    public ResultUtils NullDataOfSearchException(NullDataOfSearchException e) {
        // 分页 统一返回{count:xx,list:[]}格式
        HashMap<String, Object> map = new HashMap<>();
        map.put("count", 0);
        map.put("list", new ArrayList<>());
        return ResultUtils.of(e.getCode(), e.getMessage(), map, System.currentTimeMillis() / 1000);
    }

    /**
     * @param returnType
     * @param converterType
     * @return boolean
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/4/24 22:29
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    /**
     * 统一返回
     *
     * @param body
     * @param returnType
     * @param selectedContentType
     * @param selectedConverterType
     * @param request
     * @param response
     * @return Object
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/4/24 22:29
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // spring-boot-admin-client
        String uri = ((ServletServerHttpRequest) request).getServletRequest().getRequestURI();
        if (uri.contains("/actuator")) {
            return body;
        }
        if (body instanceof ResultUtils) {
            return body;
        }
        if (body instanceof IPage) {
            // 分页 统一返回{count:xx,list:[]}格式
            HashMap<String, Object> map = new HashMap<>();
            map.put("count", ((IPage<?>) body).getTotal());
            map.put("list", ((IPage<?>) body).getRecords());
            body = map;
        }
        return ResultUtils.of(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), body, System.currentTimeMillis() / 1000);
    }
}
